]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
ScreenShield: add a drop shadow to the animated arrows
authorGiovanni Campagna <gcampagna@src.gnome.org>
Tue, 21 Aug 2012 19:13:33 +0000 (21:13 +0200)
committerGiovanni Campagna <gcampagna@src.gnome.org>
Sat, 1 Sep 2012 14:38:51 +0000 (16:38 +0200)
Introduce a StShadowHelper to manage drop shadows from JS (which
cannot use Cogl directly), and use it in a new StWidget-derived
JS class to draw the arrow.

https://bugzilla.gnome.org/show_bug.cgi?id=682285

data/theme/gnome-shell.css
js/ui/screenShield.js
src/st/st-shadow.c
src/st/st-shadow.h

index 3be3db90ee16572c0177fba691a5a5148ed53e71..968b2cdf8950cdcdda89b274ad3e48502e9dce16 100644 (file)
@@ -2208,11 +2208,12 @@ StButton.popup-menu-item:insensitive {
     padding-bottom: 3em;
 }
 
-.screen-shield-arrows > StDrawingArea {
+.screen-shield-arrows Gjs_Arrow {
     color: white;
     width: 80px;
     height: 48px;
     -arrow-thickness: 12px;
+    -arrow-shadow: 0 1px 1px rgba(0,0,0,0.4);
 }
 
 .screen-shield-clock {
index 32ea2da01e83d7d9fb53647db6cf18ec7faf5379..ad8ecaed4f2587f3e0931f406658eaf09c42f1be 100644 (file)
@@ -274,6 +274,62 @@ const NotificationsBox = new Lang.Class({
     },
 });
 
+const Arrow = new Lang.Class({
+    Name: 'Arrow',
+    Extends: St.Bin,
+
+    _init: function(params) {
+        this.parent(params);
+        this.x_fill = this.y_fill = true;
+        this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
+
+        this._drawingArea = new St.DrawingArea();
+        this._drawingArea.connect('repaint', Lang.bind(this, this._drawArrow));
+        this.child = this._drawingArea;
+
+        this._shadowHelper = null;
+        this._shadowWidth = this._shadowHeight = 0;
+    },
+
+    _drawArrow: function(arrow) {
+        let cr = arrow.get_context();
+        let [w, h] = arrow.get_surface_size();
+        let node = this.get_theme_node();
+        let thickness = node.get_length('-arrow-thickness');
+
+        Clutter.cairo_set_source_color(cr, node.get_foreground_color());
+
+        cr.setLineCap(Cairo.LineCap.ROUND);
+        cr.setLineWidth(thickness);
+
+        cr.moveTo(thickness / 2, h - thickness / 2);
+        cr.lineTo(w/2, thickness);
+        cr.lineTo(w - thickness / 2, h - thickness / 2);
+        cr.stroke();
+    },
+
+    vfunc_style_changed: function() {
+        let node = this.get_theme_node();
+        this._shadow = node.get_shadow('-arrow-shadow');
+        if (this._shadow)
+            this._shadowHelper = St.ShadowHelper.new(this._shadow);
+        else
+            this._shadowHelper = null;
+    },
+
+    vfunc_paint: function() {
+        if (this._shadowHelper) {
+            this._shadowHelper.update(this._drawingArea);
+
+            let allocation = this._drawingArea.get_allocation_box();
+            let paintOpacity = this._drawingArea.get_paint_opacity();
+            this._shadowHelper.paint(allocation, paintOpacity);
+        }
+
+        this._drawingArea.paint();
+    }
+});
+
 /**
  * To test screen shield, make sure to kill gnome-screensaver.
  *
@@ -318,8 +374,7 @@ const ScreenShield = new Lang.Class({
                                                   y_expand: true });
 
         for (let i = 0; i < N_ARROWS; i++) {
-            let arrow = new St.DrawingArea({ opacity: 0 });
-            arrow.connect('repaint', Lang.bind(this, this._drawArrow));
+            let arrow = new Arrow({ opacity: 0 });
             this._arrowContainer.add_actor(arrow);
         }
         this._lockScreenContents.add_actor(this._arrowContainer);
@@ -384,23 +439,6 @@ const ScreenShield = new Lang.Class({
         return true;
     },
 
-    _drawArrow: function(arrow) {
-        let cr = arrow.get_context();
-        let [w, h] = arrow.get_surface_size();
-        let node = arrow.get_theme_node();
-        let thickness = node.get_length('-arrow-thickness');
-
-        Clutter.cairo_set_source_color(cr, node.get_foreground_color());
-
-        cr.setLineCap(Cairo.LineCap.ROUND);
-        cr.setLineWidth(thickness);
-
-        cr.moveTo(thickness / 2, h - thickness / 2);
-        cr.lineTo(w/2, thickness);
-        cr.lineTo(w - thickness / 2, h - thickness / 2);
-        cr.stroke();
-    },
-
     _animateArrows: function() {
         let arrows = this._arrowContainer.get_children();
         let unitaryDelay = ARROW_ANIMATION_TIME / (arrows.length + 1);
index 9c3784a55729c8a0ef6d26e7ec5b46ec13548ec4..df1787f996efe18ae66ae9c8bb1a9ff723095e98 100644 (file)
 #include "config.h"
 
 #include "st-shadow.h"
+#include "st-private.h"
+
+G_DEFINE_BOXED_TYPE (StShadow, st_shadow, st_shadow_ref, st_shadow_unref)
+G_DEFINE_BOXED_TYPE (StShadowHelper, st_shadow_helper, st_shadow_helper_copy, st_shadow_helper_free)
 
 /**
  * SECTION: st-shadow
@@ -175,16 +179,126 @@ st_shadow_get_box (StShadow              *shadow,
                    + shadow->blur + shadow->spread;
 }
 
-GType
-st_shadow_get_type (void)
+/**
+ * SECTION:st-shadow-helper:
+ *
+ * An helper for implementing a drop shadow on a actor.
+ * The actor is expected to recreate the helper whenever its contents
+ * or size change. Then, it would call st_shadow_helper_paint() inside
+ * its paint() virtual function.
+ */
+
+struct _StShadowHelper {
+  StShadow     *shadow;
+  CoglMaterial *material;
+
+  gfloat        width;
+  gfloat        height;
+};
+
+/**
+ * st_shadow_helper_new:
+ * @shadow: a #StShadow representing the shadow properties
+ *
+ * Builds a #StShadowHelper that will build a drop shadow
+ * using @source as the mask.
+ *
+ * Returns: (transfer full): a new #StShadowHelper
+ */
+StShadowHelper *
+st_shadow_helper_new (StShadow     *shadow)
+{
+  StShadowHelper *helper;
+
+  helper = g_slice_new0 (StShadowHelper);
+  helper->shadow = st_shadow_ref (shadow);
+
+  return helper;
+}
+
+void
+st_shadow_helper_update (StShadowHelper *helper,
+                         ClutterActor   *source)
+{
+  gfloat width, height;
+
+  clutter_actor_get_size (source, &width, &height);
+
+  if (helper->material == NULL ||
+      helper->width != width ||
+      helper->height != height)
+    {
+      if (helper->material)
+        cogl_object_unref (helper->material);
+
+      helper->material = _st_create_shadow_material_from_actor (helper->shadow, source);
+      helper->width = width;
+      helper->height = height;
+    }
+}
+
+/**
+ * st_shadow_helper_copy:
+ * @helper: the #StShadowHelper to copy
+ *
+ * Returns: (transfer full): a copy of @helper
+ */
+StShadowHelper *
+st_shadow_helper_copy (StShadowHelper *helper)
 {
-  static GType _st_shadow_type = 0;
+  StShadowHelper *copy;
+
+  copy = g_slice_new (StShadowHelper);
+  *copy = *helper;
+  if (copy->material)
+    cogl_object_ref (copy->material);
+  st_shadow_ref (copy->shadow);
+
+  return copy;
+}
+
+/**
+ * st_shadow_helper_free:
+ * @helper: a #StShadowHelper
+ *
+ * Free resources associated with @helper.
+ */
+void
+st_shadow_helper_free (StShadowHelper *helper)
+{
+  if (helper->material)
+    cogl_object_unref (helper->material);
+  st_shadow_unref (helper->shadow);
+
+  g_slice_free (StShadowHelper, helper);
+}
+
+/**
+ * st_shadow_helper_paint:
+ * @helper: a #StShadowHelper
+ * @actor_box: the bounding box of the shadow
+ * @paint_opacity: the opacity at which the shadow is painted
+ *
+ * Paints the shadow associated with @helper This must only
+ * be called from the implementation of ClutterActor::paint().
+ */
+void
+st_shadow_helper_paint (StShadowHelper  *helper,
+                        ClutterActorBox *actor_box,
+                        guint8           paint_opacity)
+{
+  ClutterActorBox allocation;
+  float width, height;
+
+  clutter_actor_box_get_size (actor_box, &width, &height);
 
-  if (G_UNLIKELY (_st_shadow_type == 0))
-    _st_shadow_type =
-        g_boxed_type_register_static ("StShadow",
-                                      (GBoxedCopyFunc) st_shadow_ref,
-                                      (GBoxedFreeFunc) st_shadow_unref);
+  allocation.x1 = (width - helper->width) / 2;
+  allocation.y1 = (height - helper->height) / 2;
+  allocation.x2 = allocation.x1 + helper->width;
+  allocation.y2 = allocation.y1 + helper->height;
 
-  return _st_shadow_type;
+  _st_paint_shadow_with_opacity (helper->shadow,
+                                 helper->material,
+                                 &allocation,
+                                 paint_opacity);
 }
index 3523cdd9cb366855c1932024d3deaf1137aaf5ab..40c214958428e29a39ba26053bbc3386bdc710b8 100644 (file)
 G_BEGIN_DECLS
 
 #define ST_TYPE_SHADOW              (st_shadow_get_type ())
+#define ST_TYPE_SHADOW_HELPER       (st_shadow_get_type ())
 
 typedef struct _StShadow StShadow;
+typedef struct _StShadowHelper StShadowHelper;
 
 /**
  * StShadow:
@@ -70,6 +72,21 @@ void      st_shadow_get_box  (StShadow              *shadow,
                               const ClutterActorBox *actor_box,
                               ClutterActorBox       *shadow_box);
 
+
+GType     st_shadow_helper_get_type (void) G_GNUC_CONST;
+
+StShadowHelper *st_shadow_helper_new  (StShadow       *shadow);
+
+StShadowHelper *st_shadow_helper_copy (StShadowHelper *helper);
+void            st_shadow_helper_free (StShadowHelper *helper);
+
+void            st_shadow_helper_update (StShadowHelper *helper,
+                                         ClutterActor   *source);
+
+void            st_shadow_helper_paint (StShadowHelper  *helper,
+                                        ClutterActorBox *actor_box,
+                                        guint8           paint_opacity);
+
 G_END_DECLS
 
 #endif /* __ST_SHADOW__ */